function handle = showfreyface(X,varargin)
% showfreyface - display images of Brendan Frey's face: showfreyface(X)
%
% SHOWFREYFACE(X) assumes the matrix X is a subset of vectors from the
%   freyface data set, and plots the corresponding images row-first in
%   a single image plot, padding with zeros if needed.  It assumes
%   each vector appears as a column in X.

[Nrows,Nfaces] = size(X);
Nfacecols = [];
Nfacerows = [];

assignopts(who,varargin);

if (isempty(Nfacecols))
    Nfacecols = ceil(sqrt(Nfaces));
end

if (isempty(Nfacerows))
    Nfacerows = ceil(Nfaces/Nfacecols);
end


if Nrows ~= 20*28
    error('number of rows doesn''t correspond to a freyface');
end


if (Nfacecols*Nfacerows ~= Nfaces)
    % need to pad
    
    X(:,end+(1:Nfacecols*Nfacerows-Nfaces)) = ...
        zeros(Nrows, Nfacecols*Nfacerows-Nfaces);
end


imagesc(...
    cell2mat(...
    squeeze(...
    num2cell(...
    permute(...
    reshape(X, [20, 28, Nfacecols, Nfacerows]), ...
    [2,1,4,3]), ...
    [1,2])...
    )...
    )...
    );
colormap gray;


function remain = assignopts (opts, varargin)
% assignopts - assign optional arguments (matlab 5 or higher)
%
%   REM = ASSIGNOPTS(OPTLIST, 'VAR1', VAL1, 'VAR2', VAL2, ...)
%   assigns, in the caller's workspace, the values VAL1,VAL2,... to
%   the variables that appear in the cell array OPTLIST and that match
%   the strings 'VAR1','VAR2',... .  Any VAR-VAL pairs that do not
%   match a variable in OPTLIST are returned in the cell array REM.
%   The VAR-VAL pairs can also be passed to ASSIGNOPTS in a cell
%   array: REM = ASSIGNOPTS(OPTLIST, {'VAR1', VAL1, ...});
%
%   By default ASSIGNOPTS matches option names using the strmatch
%   defaults: matches are case sensitive, but a (unique) prefix is
%   sufficient.  If a 'VAR' string is a prefix for more than one
%   option in OPTLIST, and does not match any of them exactly, no
%   assignment occurs and the VAR-VAL pair is returned in REM.
%
%   This behaviour can be modified by preceding OPTLIST with one or
%   both of the following flags:
%      'ignorecase' implies case-insensitive matches.
%      'exact'      implies exact string matches.
%   Both together imply case-insensitive, but otherwise exact, matches.
%
%   ASSIGNOPTS useful for processing optional arguments to a function.
%   Thus in a function which starts:
%		function foo(x,y,varargin)
%		z = 0;
%		assignopts({'z'}, varargin{:});
%   the variable z can be given a non-default value by calling the
%   function thus: foo(x,y,'z',4);  When used in this way, a list
%   of currently defined variables can easily be obtained using
%   WHO.  Thus if we define:
%		function foo(x,y,varargin)
%		opt1 = 1;
%               opt2 = 2;
%		rem = assignopts('ignorecase', who, varargin);
%   and call foo(x, y, 'OPT1', 10, 'opt', 20); the variable opt1
%   will have the value 10, the variable opt2 will have the
%   (default) value 2 and the list rem will have the value {'opt',
%   20}.
%
%   See also WARNOPTS, WHO.

ignorecase = 0;
exact = 0;

% check for flags at the beginning
while (~iscell(opts))
    switch(lower(opts))
        case 'ignorecase',
            ignorecase = 1;
        case 'exact',
            exact = 1;
        otherwise,
            error(['unrecognized flag :', opts]);
    end
    
    opts = varargin{1};
    varargin = varargin{2:end};
end

% if passed cell array instead of list, deal
if length(varargin) == 1 & iscell(varargin{1})
    varargin = varargin{1};
end

if rem(length(varargin),2)~=0,
    error('Optional arguments and values must come in pairs')
end

done = zeros(1, length(varargin));

origopts = opts;
if ignorecase
    opts = lower(opts);
end

for i = 1:2:length(varargin)
    
    opt = varargin{i};
    if ignorecase
        opt = lower(opt);
    end
    
    % look for matches
    
    if exact
        match = strmatch(opt, opts, 'exact');
    else
        match = strmatch(opt, opts);
    end
    
    % if more than one matched, try for an exact match ... if this
    % fails we'll ignore this option.
    
    if (length(match) > 1)
        match = strmatch(opt, opts, 'exact');
    end
    
    % if we found a unique match, assign in the corresponding value,
    % using the *original* option name
    
    if length(match) == 1
        assignin('caller', origopts{match}, varargin{i+1});
        done(i:i+1) = 1;
    end
end

varargin(find(done)) = [];
remain = varargin;
